package __linnear_list

import (
	"errors"
	"fmt"
)

/**
顺序表
用数组实现

优点：查询一步到位
缺点：增、删、改需要移动大量元素

关于移动数组中的元素，
如果向前移动，则从前开始遍历
如果向后移动，则从后开始遍历
*/

const maxSize = 10 // 默认长度为10

type SqList struct {
	data   [maxSize]int // 用数组保存
	Length int          // 存值的长度
}

func NewSqList() *SqList {
	return &SqList{}
}

// AddElement 在末尾添加元素
// 如果列表已满 -> -1
// 成功 -> 下标值
func (s *SqList) AddElement(e int) int {
	// 判断数组越界
	if s.Length >= maxSize {
		// 或者扩容，但是没想到好的办法
		return -1
		//panic("数组满了")
	}
	s.data[s.Length] = e
	s.Length++
	return s.Length - 1
}

// InsertElement 在 i 位置插入元素
// 如果 i 不符合规则 -> -1
// 成功 -> 0
func (s *SqList) InsertElement(e, i int) int {
	if !s.indexLegal(i) {
		return -1
	}
	// 将i之后的位置后移
	// 如果满了，则抛弃最后一位
	// 如果没满，则后移
	lastIndex := s.Length
	if s.Length == maxSize {
		lastIndex = s.Length - 1
	}
	for j := lastIndex; j > i; j-- {
		s.data[j] = s.data[j-1]
	}
	s.data[i] = e
	s.Length++
	return 0
}

// DeleteElement 删除第一个匹配的元素
// 成功 -> 下标值
// 失败 -> -1
func (s *SqList) DeleteElement(e int) int {
	index := -1
	for i := 0; i < s.Length; i++ {
		if s.data[i] == e {
			index = i
			break
		}
	}
	if index != -1 {
		// 将元素左移一位
		for i := index; i < s.Length-1; i++ {
			s.data[i] = s.data[i+1]
		}
		s.Length--
	}
	return index
}

// DeleteIndex 删除下标为i的值
// 成功 -> 值
// i 不符合规则 -> error
func (s *SqList) DeleteIndex(i int) (int, error) {
	if !s.indexLegal(i) {
		return -1, errors.New("下标不在范围内")
	}
	e := s.data[i]
	r := s.DeleteElement(e)
	if r == -1 {
		return 0, errors.New("删除出错")
	}
	return e, nil
}

// Update 更新元素
// 成功 -> 0
// i 不符合规则 -> -1
func (s *SqList) Update(e, i int) int {
	if !s.indexLegal(i) {
		return -1
	}
	s.data[i] = e
	return 0
}

// GetElement 根据下标获取元素
// 成功 -> 值
// i 不符合规则 -> error
func (s *SqList) GetElement(i int) (int, error) {
	if !s.indexLegal(i) {
		return -1, errors.New("下标不在范围内")
	}
	return s.data[i], nil
}

// LocateElement 查找第一个与 e 相等的元素
// 成功 -> 下标
// 失败 -> -1
func (s *SqList) LocateElement(e int) int {
	r := -1
	for i, v := range s.data {
		if e == v {
			r = i
			break
		}
	}
	return r
}

// IsEmpty 判断是否为空
func (s *SqList) IsEmpty() bool {
	return s.Length == 0
}

// Clear 清空线性表
func (s *SqList) Clear() {
	if s.IsEmpty() {
		return
	}
	s.Length = 0
}

// indexLegal 下标是否符合规则
func (s *SqList) indexLegal(i int) bool {
	return 0 <= i && i <= s.Length
}

// 重写打印方法
func (s SqList) String() string {
	var d []int
	for i := 0; i < s.Length; i++ {
		d = append(d, s.data[i])
	}
	return fmt.Sprintf("data->%v, length->%d", d, s.Length)
}
